/*
 * Copyright 2009 Andreas Borglin andreas.borglin@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package borge.mobile.app.jakoon;

import borge.mobile.lib.pimp.ImageConstants;
import borge.mobile.lib.pimp.ImageCreator;
import borge.mobile.lib.pimp.ImageEffectException;
import borge.mobile.lib.pimp.ImageManager;
import borge.mobile.lib.pimp.OverlayBounds;
import borge.mobile.lib.pimp.ProgressListener;
import borge.mobile.app.jakoon.Main.ESwtExecutor;
import borge.mobile.app.jakoon.SaveForm.SaveData;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import org.eclipse.ercp.swt.mobile.Screen;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.MessageBox;


/**
 * Form for handling all image related actions
 * @author Andreas Borglin
 */
public class ImageForm implements ImageConstants, ImageCreator, ProgressListener {

    private Composite composite;
    private Composite canvasComp;
    private ImageManager imageManager;
    private ImageCanvas canvas;
    private ESwtExecutor executor;
    private ImageBottomForm imageBottomForm;

    private static final String FILE_URI = "file:///";
    
    protected ImageForm(ESwtExecutor exec, Composite comp) {
        executor = exec;
        composite = comp;
        
        initCanvas();
        initImageHandler(false);
    }
    
    protected static boolean isPlatformSupported(){
        return ImageManager.isPlatformSupported();
    }
    
    protected void makeVisible(boolean startOver){
        canvasComp.setVisible(true);
        canvas.setVisible(true);
        
        if(startOver)
            initImageHandler(true);
    }
    
    private void handleError(String error){
        canvasComp.setVisible(false);
        canvas.setVisible(false);
        executor.loadErrorForm(error);
    }
    
    private void initCanvas() {
        
        canvasComp = new Composite(composite, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 1;
        canvasComp.setLayout(layout);
        
        canvas = new ImageCanvas(canvasComp, executor.getDisplay(), this);

        GridData data = new GridData();
        data.widthHint = Main.SUPPORTED_LANDSCAPE_WIDTH;
        data.heightHint = Main.SUPPORTED_LANDSCAPE_HEIGHT;
        data.horizontalAlignment = GridData.FILL;
        canvas.setLayoutData(data);
       
        canvas.layout();
        canvasComp.layout(); 
        
    }
    
    protected void loadBottomForm(){

        if(imageBottomForm == null)
            imageBottomForm = new ImageBottomForm(executor, canvasComp, this);
        else{
            imageBottomForm.reset();
            imageBottomForm.setVisible(true);
        }

        // Resize canvas so we can fit in a form below
        resizeCanvas(Main.SUPPORTED_LANDSCAPE_WIDTH, Main.SUPPORTED_LANDSCAPE_HEIGHT - 60);
        
    }
    
    protected void bottomFormCallback(int result){
        
        if(imageBottomForm != null)
            imageBottomForm.setVisible(false);
        
        resizeCanvas(Main.SUPPORTED_LANDSCAPE_WIDTH, Main.SUPPORTED_LANDSCAPE_HEIGHT);
        canvas.bottomFormUnloaded();

        // If value was changed by user
        if(result != ImageBottomForm.DEFAULT_INTERNAL)
            applyChange(result);
    }
    
    protected void resizeCanvas(int width, int height){
     
        GridData data = (GridData)canvas.getLayoutData();
        data.widthHint = width;
        data.heightHint = height;
        
        canvas.layout();
        canvasComp.layout();
        composite.layout();
    }
    
    protected void initImageHandler(boolean reset){
        
        // If we are starting over,
        // reset canvas, but re-create ImageManager
        if(reset){
            canvas.reset();
        }
        
        imageManager = new ImageManager();
        
        // Query for input image
        // Unfortunately filter extensions are not supported on S60 eSWT
        String[] filter = {"*.jpg", "*.jpeg", "*.gif", "*.png", "*.bmp"};
        FileDialog fd = new FileDialog(executor.getShell(), SWT.OPEN);
        fd.setFilterPath(executor.getDefaultPath());
        fd.setFilterExtensions(filter);
        fd.setText("Choose image");
        String result = fd.open();
        
        // If Cancel, exit app
        if(result == null){
            executor.exit();
            return;
        }
        String path = FILE_URI + result;
        path = path.replace('\\', '/');

        try {
            imageManager.initialize(path);
        }
        catch(ImageEffectException e){
            // Means something wrong with input file
            handleError(e.toString());
            return;
        }
        catch(Error e){
            handleError("File data not supported");
            return;
        }
        
        try{
            // must be set after init
            imageManager.setImageCreator(this);
            canvas.setImageManager(imageManager);

            int imgW = imageManager.getPreviewImageWidth();
            int imgH = imageManager.getPreviewImageHeight();
            if (imgW > imgH) {
                executor.getScreen().setOrientation(Screen.LANDSCAPE);
            }

            Rectangle rec = executor.getScreen().getBounds();
            imageManager.scalePreviewImage(rec.width, rec.height);

            canvas.setSupport(imageManager.getSupportInfo());
            canvas.setImage(imageManager.getCurrentImageStream());

            canvas.redraw();
        } 
        catch (Exception e) {
            handleError(e.toString());
        }

    }

    
    protected void undo(){
        imageManager.undo();
        canvas.setImage(imageManager.getCurrentImageStream());
        if(canvas.isVisible())
            canvas.redraw();
    }
    
    protected void saveImage(SaveData saveData){
        
        String dir = saveData.directory.replace('\\', '/');
        if(!dir.endsWith("/")){
            dir += "/";
        }
        String filepath = FILE_URI + dir + saveData.filename;
        filepath = filepath.replace('\\', '/');
        
        // TEMP
        //filepath += "2";
        
        try{            
            // We need to resize if needed
            // Values have been verified in SaveForm
            // No need to actually apply changes for preview...
            if(saveData.inPercent){
                int percent = saveData.sizeValOne;
                if(percent != 100){
                    imageManager.opResize(percent);
                }
            }
            else{
                int width = saveData.sizeValOne;
                int height = saveData.sizeValTwo;
                if(width != imageManager.getCurrentRealWidth() ||
                        height != imageManager.getCurrentRealHeight()){
                    
                    imageManager.opResize(width, height, false);
                    
                }
            }
            
            // return if no changes have been made..nothing to do
            if(!imageManager.changesMade()){
                MessageBox mb = new MessageBox(executor.getShell(), SWT.ICON_WARNING);
                mb.setMessage("No changes have been made.");
                mb.open();
                executor.loadImageForm(false);
                return;
            }
            
            FileConnection fc = (FileConnection)Connector.open(filepath, Connector.READ);
            if(!saveData.overwrite && fc.exists()){
                MessageBox mb = new MessageBox(executor.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO);
                mb.setMessage("File exists and Overwrite option not set.\n" +
                        "Do you want to write over: " + dir+saveData.filename + "?");
                int choice = mb.open();
                if(choice == SWT.NO)
                    return;
            }
            
            
            executor.loadProgressForm(UNKNOWN);
            imageManager.writeChangesToFile(filepath, saveData.format, this);
        }
        catch(Exception e){
            e.printStackTrace();
            // find a generic way to handle errors..
            handleError(e.toString());
        }
        
        
        
    }
    
    protected void save(){
        
        canvasComp.setVisible(false);
        canvas.setVisible(false);
        executor.loadSaveForm(getDirPath(imageManager.getInputImagePath()), 
                getFileName(imageManager.getInputImagePath()), 
                imageManager.getSupportedOutputFormats());
        
    }

    /*
     * Upload image to online service
     * Currently not supported
     */
    protected void upload(){
        canvasComp.setVisible(false);
        canvas.setVisible(false);
        executor.loadUploadForm();
        
    }

    protected void loadManipulatorForm(Image image){
        canvasComp.setVisible(false);
        canvas.setVisible(false);
        String[] list = imageManager.getSupportInfo().getImageOperation(WHITEBALANCE).getSupportedModes();
        executor.loadImageManipulatorForm(image, list);
    }

    private String getDirPath(String file){
        int last = file.lastIndexOf('/');
        int start = FILE_URI.length();
        return file.substring(start, last+1);
    }
    
    private String getFileName(String file){
        int last = file.lastIndexOf('/');
        return file.substring(last+1, file.length());
    }
    
    protected OverlayBounds loadOverlayImage(){
        
        try{
            FileDialog fd = new FileDialog(executor.getShell(), SWT.OPEN);
            String path = FILE_URI + fd.open();
            path = path.replace('\\', '/');
            OverlayBounds ob = imageManager.createOverlayImage(path);
            return ob;
        }
        catch(Exception e){
            e.printStackTrace();
            handleError(e.toString());
        }
        
        return null;
    }
    
    public Object createImage(InputStream is){
        Image image = new Image(executor.getDisplay(), is);
        return image;
    }

    protected void applyChange(int arrIndex) {

        try {

            switch (Data.commandMode) {
                
                case RESIZE: {
                    imageManager.opResize(arrIndex);
                    break;
                }

                case ROTATE: {
                    imageManager.opRotate(arrIndex+1);
                    break;
                }

                case FLIP: {
                    
                    if (arrIndex == 0) {
                        imageManager.opFlip(FLIP_HORIZONTALLY);
                    } 
                    else {
                        imageManager.opFlip(FLIP_VERTICALLY);
                    }

                    break;
                }

                case BRIGHTNESS: {
                    imageManager.opSetBrightness(arrIndex);
                    break;
                }

                case CONTRAST: {
                    imageManager.opSetContrast(arrIndex);
                    break;
                }

                case FRAME: {
                    int width = Data.mouseDragX - Data.mouseDownX;
                    int height = Data.mouseDragY - Data.mouseDownY;
                    int curw = imageManager.getPreviewImageWidth();
                    int curh = imageManager.getPreviewImageHeight();

                    int xw = (curw - width) / 2;
                    int yh = (curh - height) / 2;
                    imageManager.opFrame(xw, yh);
                    break;
                }

                case CROP: {
                    int xpos = Data.mouseDownX - Data.imageStartX;
                    int ypos = Data.mouseDownY - Data.imageStartY;
                    int width = Data.mouseDragX - Data.mouseDownX;
                    int height = Data.mouseDragY - Data.mouseDownY;

                    imageManager.opCrop(xpos, ypos, width, height);
                    break;
                }

                case EFFECT: {
                    imageManager.opApplyEffect(arrIndex);
                    break;
                }

                case WHITEBALANCE: {
                    imageManager.opSetWhiteBalance(arrIndex);
                    break;
                }
                
                case OVERLAY: {
                    int imgX = Data.mouseDragX - Data.imageStartX;
                    int imgY = Data.mouseDragY - Data.imageStartY;
                    imageManager.opAddOverlayImage(imgX, imgY);
                    break;
                }


            }

            imageManager.applyChanges();
            canvas.setImage(imageManager.getCurrentImageStream());
            
            if(canvas.isVisible())
                canvas.redraw();
        }
        catch (Exception e) {
            e.printStackTrace();
            handleError(e.toString());
        }

    }

    protected Image getCurrentImage(){
        return canvas.getCurrentImage();
    }

    // From ProgressListener interface
    public void stepUpdate(String step, int curStep, int totalSteps){
        executor.updateProgress(curStep, totalSteps, step, null);
    }
    
    public void taskFinished(boolean success, String errorMsg){
        executor.updateProgress(1, 1, new Boolean(success).toString(), errorMsg);
    }

    // This method can be called from any thread to make the event loop to exit. 
    protected void exit() {
        executor.exit();
    }
}
